/* Hello World Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include "driver/gpio.h"
#include "esp_app_format.h"
#include "esp_flash_partitions.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include <stdio.h>

#include "config_app.h"
#include "device_app.h"
#include "ingwaycomm.h"
#include "uart_svc.h"

#include "DiDo.h"
#include "ble_tsk.h"
#include "blink.h"
#include "comm1_tsk.h"
#include "comm2_tsk.h"
#include "devdisc_tsk.h"
#include "key.h"
#include "udp_brdcast.h"
#include "wifi_connect.h"

#include "esp_efuse.h"
#include "eth_connect.h"
#include "networkBase.h"
#include "tcpSocket_tsk.h"

#include "J_http.h"
#include "tcp_log.h"
static const char* TAG = "Main";
#define HASH_LEN 32 /* SHA-256 digest length */
SystemFucntionTPDF tSystemFucntion;
/* Send MyQueueDataTPDF structure data to a specified message Queue.
 * like mqtt task, socket task */
static uint8_t Main_vRequest_From_Ram(DeviceTPDF* tDev, MyQueueDataTPDF* tMyQueueDataUp, QueueHandle_t mSendTOQueue)
{
    uint16_t i;
    uint16_t* tData = DEV_dGet_Mem(tDev, tMyQueueDataUp->tMyQueueCommand.usRegAddr, tMyQueueDataUp->tMyQueueCommand.usRegLen);
    if (tData) {
        for (i = 0; i < tMyQueueDataUp->tMyQueueCommand.usRegLen; i++) {
            tMyQueueDataUp->tMyQueueCommand.cData[i * 2] = (tData[i] >> 8) & 0x00ff;
            tMyQueueDataUp->tMyQueueCommand.cData[i * 2 + 1] = tData[i] & 0x00ff;
        }
        tMyQueueDataUp->tMyQueueCommand.usDatalen = tMyQueueDataUp->tMyQueueCommand.usRegLen * 2;
        xQueueSend(mSendTOQueue, (void*)tMyQueueDataUp, (TickType_t)0);
        return (1);
    }
    return (0);
}

/* Send MyQueueDataTPDF structure data to down port, like com1, com2, ble.etc.
 * And waiting return data from the down port with in timeout */
static uint8_t Main_vRequest_From_Down(DeviceTPDF* tDev, MyQueueDataTPDF* tMyQueueDataUp)
{
    uint16_t usDelay;
    switch (tDev->tDeviceConfig.usCommPort) {
    case DEVICE_COMMPORT_TYPE_COM1:
        xQueueSend(mComm1QueueSend, (void*)tMyQueueDataUp, (TickType_t)0);
        if (tMyQueueDataUp->tMyQueueCommand.tMyQueueCommandType == MultiDeviceCtrl) {
            usDelay = 800;
        } else {
            usDelay = mPartitionTable.tEthernetConfig.EthernetTimeout / 10;
        }
        if (ANA_LOG) {
            ESP_LOGI(TAG, "Send tMyQueueDataUp data to mComm1QueueSend");
        }

        while (usDelay) {
            vTaskDelay(1);
            usDelay--;
            if (xQueueReceive(mComm1QueueRec, (void*)tMyQueueDataUp, (portTickType)0)) {
                break;
            }
        }
        if (!usDelay) {
            return (0);
        }
        return (1);
    case DEVICE_COMMPORT_TYPE_COM2:
        xQueueSend(mComm2QueueSend, (void*)tMyQueueDataUp, (TickType_t)0);
        usDelay = mPartitionTable.tEthernetConfig.EthernetTimeout / 10;
        ESP_LOGI(TAG, "Send tMyQueueDataUp data to mComm2QueueSend");
        while (usDelay) {
            vTaskDelay(1);
            usDelay--;
            if (xQueueReceive(mComm2QueueRec, (void*)tMyQueueDataUp, (portTickType)0)) {
                break;
            }
        }
        if (!usDelay) {
            return (0);
        }
        return (1);
    case DEVICE_COMMPORT_TYPE_CAN:
        break;
    case DEVICE_COMMPORT_TYPE_BLE:
        xQueueSend(mBleQueueSend, (void*)tMyQueueDataUp, (TickType_t)0);
        usDelay = mPartitionTable.tEthernetConfig.EthernetTimeout;
        while (usDelay) {
            vTaskDelay(1);
            usDelay--;
            if (xQueueReceive(mBleQueueRec, (void*)tMyQueueDataUp, (portTickType)0)) {
                break;
            }
        }
        if (!usDelay) {
            return (0);
        }
        return (1);
    }
    return (0);
}

static void Main_Eth_Process(void)
{
    MyQueueDataTPDF tMyQueueDataUp;
    DeviceTPDF* tDev;
    if (xQueueReceive(mEthQueueRec, (void*)&tMyQueueDataUp, (portTickType)0)) {
        if (tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == Sntp) {
            xQueueSend(mComm1QueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
            return;
        } else if (tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == DeviceDiscoveryReStart
            || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == DeviceDiscoveryContinue
            || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == DeviceDiscoveryStop) {
            ESP_LOGW(TAG, "tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType:0x%02x", tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType);
            xQueueSend(mDevDiscQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
            return;
        }
        if (ANA_LOG) {
            ESP_LOGI(TAG, "Data to device address:0x%x", tMyQueueDataUp.tMyQueueCommand.usSlaveAddr);
        }
        tDev = DEV_dFind_By_ConvertAddr(tMyQueueDataUp.tMyQueueCommand.usSlaveAddr);
        if (!tDev) {
            /* if don't add device, the code means passthrough Modbus TCP-RTU data */
            if (tMyQueueDataUp.tMyQueueCommand.usSlaveAddr <= 2) {
                ESP_LOGI(TAG, "Gateway modbus address:0x%02x", mPartitionTable.GatewayInfor.ModbusAddr);
            } else if (tMyQueueDataUp.tMyQueueCommand.usSlaveAddr >= 3 && tMyQueueDataUp.tMyQueueCommand.usSlaveAddr <= 255) {
                DeviceTPDF tDevVrt;
                tDevVrt.tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM1;
                if (Main_vRequest_From_Down(&tDevVrt, &tMyQueueDataUp)) {
                    xQueueSend(mEthQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
                }
            }
            // else if (tMyQueueDataUp.tMyQueueCommand.usSlaveAddr >= 101 && tMyQueueDataUp.tMyQueueCommand.usSlaveAddr <= 200) {
            //     DeviceTPDF tDevVrt;
            //     tDevVrt.tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM2;
            //     if (Main_vRequest_From_Down(&tDevVrt, &tMyQueueDataUp)) {
            //         xQueueSend(mEthQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
            //     }
            // }
            return;
        }
        if (mPartitionTable.usGatewayRunMode == GATEWAY_MODE_TRANSMIT
            && (tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadCoil
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadInput
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadReg
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadInputReg)) {
            if (Main_vRequest_From_Ram(tDev, &tMyQueueDataUp, mEthQueueSend)) {
                return;
            }
        }
        if (Main_vRequest_From_Down(tDev, &tMyQueueDataUp)) {
            xQueueSend(mEthQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
        }
    }
}

static void Main_Ble_Process(void)
{
    MyQueueDataTPDF tMyQueueDataUp;
    DeviceTPDF* tDev;
    if (xQueueReceive(mBleQueueRec, (void*)&tMyQueueDataUp, (portTickType)0)) {
        tDev = DEV_dFind_By_ConvertAddr(tMyQueueDataUp.tMyQueueCommand.usSlaveAddr);
        if (!tDev) {
            /* if don't add device, the code means passthrough BLE Modbus RTU - UART Modbus RTU data */
            if (tMyQueueDataUp.tMyQueueCommand.usSlaveAddr >= 3 && tMyQueueDataUp.tMyQueueCommand.usSlaveAddr <= 100) {
                DeviceTPDF tDevVrt;
                tDevVrt.tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM1;
                if (Main_vRequest_From_Down(&tDevVrt, &tMyQueueDataUp)) {
                    xQueueSend(mSBleQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
                }
            } else if (tMyQueueDataUp.tMyQueueCommand.usSlaveAddr >= 101 && tMyQueueDataUp.tMyQueueCommand.usSlaveAddr <= 200) {

                DeviceTPDF tDevVrt;
                tDevVrt.tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM2;
                if (Main_vRequest_From_Down(&tDevVrt, &tMyQueueDataUp)) {
                    xQueueSend(mSBleQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
                }
            }
            return;
        }
        if (mPartitionTable.usGatewayRunMode == GATEWAY_MODE_TRANSMIT
            && (tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadCoil
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadInput
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadReg
                || tMyQueueDataUp.tMyQueueCommand.tMyQueueCommandType == ReadInputReg)) {
            if (Main_vRequest_From_Ram(tDev, &tMyQueueDataUp, mEthQueueSend)) {
                return;
            }
        }
        if (Main_vRequest_From_Down(tDev, &tMyQueueDataUp)) {
            ESP_LOGW("MAIN_BLE_PROCESS", "MAIN_BLE_PROCESS check 444444");
            xQueueSend(mSBleQueueSend, (void*)&tMyQueueDataUp, (TickType_t)0);
        }
    }
}

static void Main_Task(void* pvParameters)
{
    while (1) {
        vTaskDelay(1);
        Main_Eth_Process();
        // Main_Wifi_Process();
        Main_Ble_Process();
    }
}

void test(void)
{
    mDevice[0].tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM1;
    mDevice[0].tDeviceConfig.usMainType = DEVICE_MAIN_TYPE_CHINT_MCB;
    mDevice[0].tDeviceConfig.usConvertAddr = 1;

    mDevice[1].tDeviceConfig.usCommPort = DEVICE_COMMPORT_TYPE_COM1;
    mDevice[1].tDeviceConfig.usMainType = DEVICE_MAIN_TYPE_CHINT_MCB;
    mDevice[1].tDeviceConfig.usConvertAddr = 2;
}

static void Main_Create_Task_Queue()
{
    mComm1QueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mComm1QueueRec = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mComm2QueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mComm2QueueRec = xQueueCreate(1, sizeof(MyQueueDataTPDF));

    mEthQueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mEthQueueRec = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    // mWifiQueueSend = xQueueCreate(1,sizeof(MyQueueDataTPDF));
    // mWifiQueueRec = xQueueCreate(1,sizeof(MyQueueDataTPDF));

    mBleQueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mSBleQueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mBleQueueRec = xQueueCreate(1, sizeof(MyQueueDataTPDF));

    mDevDiscQueueSend = xQueueCreate(1, sizeof(MyQueueDataTPDF));
    mDevDiscQueueRec = xQueueCreate(1, sizeof(MyQueueDataTPDF));
}

static void Main_Hardware_Config()
{
    uint32_t uiFunction = 0;

    uiFunction = (uint32_t)mPartitionTable.usFunctionH << 16U | (uint32_t)mPartitionTable.usFunctionL;
    ESP_LOGI(TAG, "uiFunction:%x", uiFunction);

    xTaskCreate(sytem_blink_task, "blink", 2048, NULL, 5, NULL);
    xTaskCreate(vKey_task, "key task", 3072, NULL, 5, NULL);

    if ((uiFunction & (0x3 << 8)) >> 8 == 0x01) // 0x3 << 8 take BLE state
    {
        tSystemFucntion.ucBleEnable = FUNCTION_WORK;
        xTaskCreate(Ble_vTsk_Start, "ble task", 4096, NULL, 4, NULL);
    } else {
        tSystemFucntion.ucBleEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "BLE function NOT run!");
    }

    if ((uiFunction & (0x3 << 6)) >> 6 == 0x01) // 0x3 << 6 take ETH state
    {
        tSystemFucntion.ucEthEnable = FUNCTION_WORK;
        vNetworkBaseInit();
        // vETH init()
        vETH_Init();
        // socket init()   task
        xTaskCreate(vSocket_vTsk_Start, "tcp socket task", 1024 * 6, NULL, 4, NULL);
    } else {
        tSystemFucntion.ucEthEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "Ethernet function NOT run!");
    }

    if ((uiFunction & (0x3 << 0)) >> 0 == 0x01) // 0x3 take COM1 state
    {
        tSystemFucntion.ucCom1Enable = FUNCTION_WORK;
        xTaskCreate(COM1_vTsk_Start, "comm1 task", 4096, NULL, 4, NULL);
    } else {
        tSystemFucntion.ucCom1Enable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "COM1 function NOT run!");
    }

    if ((uiFunction & (0x3 << 2)) >> 2 == 0x01) // 0x3 << 2 take COM2 state
    {
        tSystemFucntion.ucCom2Enable = FUNCTION_WORK;
        // xTaskCreate(COM2_vTsk_Start, "comm2 task", 4096, NULL, 4, NULL);
    } else {
        tSystemFucntion.ucCom2Enable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "COM2 function NOT run!");
    }

    if ((uiFunction & (0x3 << 4)) >> 4 == 0x01) // 0x3 << 4 take CAN state
    {
        tSystemFucntion.ucCanEnable = FUNCTION_WORK;
    } else {
        tSystemFucntion.ucCanEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "CAN function NOT run!");
    }

    if ((uiFunction & (0x3 << 10)) >> 10 == 0x01) // 0x3 << 10 take WIFI state
    {
        tSystemFucntion.ucWifiEnable = FUNCTION_WORK;
        vNetworkBaseInit();
        // wifi init()
        vWIFI_Init();
        // socket init()   task
        if (mPartitionTable.tWifiConfig.usMode == WIFI_MODE_STA || mPartitionTable.tWifiConfig.usMode == WIFI_MODE_APSTA) {
            xTaskCreate(vSocket_vTsk_Start, "tcp socket task", 1024 * 6, NULL, 4, NULL);
        }

    } else {
        tSystemFucntion.ucWifiEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "WIFI function NOT run!");
    }

    if ((uiFunction & (0x3 << 12)) >> 12 == 0x01) // 0x3 << 12 take IOT state
    {
        tSystemFucntion.ucIotEnable = FUNCTION_WORK;
    } else {
        tSystemFucntion.ucIotEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "IOT function NOT run!");
    }

    if ((uiFunction & (0x3 << 14)) >> 14 == 0x01) // 0x3 << 14 take DI_DO state
    {
        tSystemFucntion.ucDiDOEnable = FUNCTION_WORK;
        xTaskCreate(vDiDo_task, "DiDo task", 2048, NULL, 5, NULL);
    } else {
        tSystemFucntion.ucDiDOEnable = FUNCTION_IDLE;
        ESP_LOGE(TAG, "DI/DO function NOT run!");
    }

    xTaskCreate(Main_Task, "main task", 4096, NULL, 4, NULL);
    // xTaskCreate(DEVDISC_Task, "devdisc task", 4096, NULL, 4, NULL);
    xTaskCreate(tcp_log_task, "tcp_log_task", 4096, AF_INET, 6, NULL);
    xTaskCreate(key_open_ap_task, "key_open_ap_task", 4096, NULL, 6, NULL);
}

extern const esp_efuse_desc_t* ESP_EFUSE_HW_VERSION_1[];
extern const esp_efuse_desc_t* ESP_EFUSE_HW_VERSION_2[];
extern const esp_efuse_desc_t* ESP_EFUSE_HW_VERSION_3[];
extern const esp_efuse_desc_t* SN_ZONE[];
uint8_t ef_hw_read[3] = { 0 };
uint8_t ef_sn_read[24] = { 0 };
static void Main_Write_Vesion_Number_To_NVS()
{
    uint8_t ucRunVersionCal[4];
    uint8_t ucAppVer[2];
    uint16_t usAppVersion;

    /* version get from esp_app_desc_t structure */
    const esp_partition_t* running = esp_ota_get_running_partition();
    esp_app_desc_t running_app_info;
    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {

        ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
    }
    uint8_t dot = 0;
    for (int i = 0; running_app_info.version[i] != '\0'; i++) {
        if (running_app_info.version[i] == '.') {
            dot++;
        }
        if (dot == 2) {
            running_app_info.version[i] = '\0';
            break;
        }
    }
    ESP_LOGI(TAG, "get 1 dot firmware version: %s", running_app_info.version);
    Version_Cal(running_app_info.version, (char*)ucRunVersionCal);

    ucAppVer[0] = (ucRunVersionCal[0] - '0') * 10 + (ucRunVersionCal[1] - '0');
    ucAppVer[1] = (ucRunVersionCal[2] - '0') * 10 + (ucRunVersionCal[3] - '0');
    usAppVersion = ((uint16_t)ucAppVer[0] << 8U) | (uint16_t)ucAppVer[1];
    ESP_LOGI(TAG, "usAppVersion: 0x%04x", usAppVersion);

    if (mPartitionTable.ReserveConfig.Version != usAppVersion) {
        mPartitionTable.ReserveConfig.Version = usAppVersion;
        /* write version to NVS Flash */
        CFG_vSaveConfig(0x1fe);
    }

    // if(mPartitionTable.BasicInfor.HardwareVersion != usAppVersion)
    // {
    // 	mPartitionTable.BasicInfor.HardwareVersion = 0x0203;//SMG-ESR DC48V version
    // 	CFG_vSaveConfig(0x020E - 1);
    // }

    if (mPartitionTable.BasicInfor.SoftwareVersion != usAppVersion) {
        mPartitionTable.BasicInfor.SoftwareVersion = usAppVersion;
        CFG_vSaveConfig(0x020D - 1);
    }

    ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_HW_VERSION_1, &ef_hw_read[0], 8));
    ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_HW_VERSION_2, &ef_hw_read[1], 8));
    ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_HW_VERSION_3, &ef_hw_read[2], 8));
    mPartitionTable.BasicInfor.HardwareVersion = (ef_hw_read[0] << 8) | ef_hw_read[1];

    ESP_ERROR_CHECK(esp_efuse_read_field_blob(SN_ZONE, ef_sn_read, 8 * 24));
    uint8_t* s = mPartitionTable.BasicInfor.ProductSN;
    for (uint8_t i = 0; i < 12; i++) {
        *(s++) = ef_sn_read[i * 2 + 1];
        *(s++) = ef_sn_read[i * 2];
    }
    ESP_LOGE("efuse", "HW Version : V%d.%d.%d", ef_hw_read[0], ef_hw_read[1], ef_hw_read[2]);
    ESP_LOGE("efuse", "Device SN  : %s", ef_sn_read);
}

static void Main_Get_ESP32_MAC_Addr()
{
    uint16_t uiIndex;
    uint16_t uiSize;
    int tmp;
    // Get the derived MAC address for each network interface
    uint8_t derived_mac_addr[6] = { 0 };
    uint8_t re_derived_mac_addr[6] = { 0 };
    memset(tcp_info_buff, 0, sizeof(J_tcp_connect_info_t) * TCP_INFO_SIZE);
    // Get MAC address for WiFi Station interface
    ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_WIFI_STA));
    ESP_LOGW("WIFI_STA MAC", "\t0x %02x %02x %02x %02x %02x %02x",
        derived_mac_addr[0], derived_mac_addr[1], derived_mac_addr[2],
        derived_mac_addr[3], derived_mac_addr[4], derived_mac_addr[5]);
    // store reverse MAC bytes with 2 bytes
    for (int i = 0; i < 3; i++) {
        tmp = derived_mac_addr[2 * i];
        re_derived_mac_addr[2 * i] = derived_mac_addr[2 * i + 1];
        re_derived_mac_addr[2 * i + 1] = tmp;
    }

    /* write wifi sta MAC address infor to nvs flash */
    // esp_log_buffer_hex(TAG,mPartitionTable.BasicInfor.ProductDescription,6);
    if (memcmp(mPartitionTable.BasicInfor.ProductDescription, re_derived_mac_addr, 6) != 0) {
        for (int i = 0; i < 3; i++) {
            mPartitionTable.BasicInfor.ProductDescription[i] = (derived_mac_addr[2 * i] << 8) + derived_mac_addr[2 * i + 1];
        }
        uiIndex = 0x021B - 1; // wifi sta MAC start address: 0x021B - 1, temporary storage Product Description
        uiSize = 3;
        while (uiSize) {
            CFG_vSaveConfig(uiIndex++);
            uiSize--;
        }
    } else {
        ESP_LOGI(TAG, "sta MAC already storaged in ProductDescription area.");
    }

    // Get MAC address for SoftAp interface
    ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_WIFI_SOFTAP));
    ESP_LOGW("SoftAP MAC", "\t0x %02x %02x %02x %02x %02x %02x",
        derived_mac_addr[0], derived_mac_addr[1], derived_mac_addr[2],
        derived_mac_addr[3], derived_mac_addr[4], derived_mac_addr[5]);
    // store reverse MAC bytes with 2 bytes
    for (int i = 0; i < 3; i++) {
        tmp = derived_mac_addr[2 * i];
        re_derived_mac_addr[2 * i] = derived_mac_addr[2 * i + 1];
        re_derived_mac_addr[2 * i + 1] = tmp;
    }

    /* write wifi softAP MAC address infor to nvs flash */
    if (memcmp(mPartitionTable.BasicInfor.ProductDescription + 3, re_derived_mac_addr, 6) != 0) {
        for (int i = 0; i < 3; i++) {
            mPartitionTable.BasicInfor.ProductDescription[3 + i] = (derived_mac_addr[2 * i] << 8) + derived_mac_addr[2 * i + 1];
        }
        uiIndex = 0x021E - 1; // wifi softAP MAC start address: 0x021E - 1, temporary storage Product Description
        uiSize = 3;
        while (uiSize) {
            CFG_vSaveConfig(uiIndex++);
            uiSize--;
        }
    } else {
        ESP_LOGI(TAG, "softAP MAC already storaged in ProductDescription area.");
    }

    // Get MAC address for Bluetooth
    ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_BT));
    ESP_LOGW("BT MAC", "\t0x %02x %02x %02x %02x %02x %02x",
        derived_mac_addr[0], derived_mac_addr[1], derived_mac_addr[2],
        derived_mac_addr[3], derived_mac_addr[4], derived_mac_addr[5]);
    // store reverse MAC bytes with 2 bytes
    for (int i = 0; i < 3; i++) {
        tmp = derived_mac_addr[2 * i];
        re_derived_mac_addr[2 * i] = derived_mac_addr[2 * i + 1];
        re_derived_mac_addr[2 * i + 1] = tmp;
    }

    /* write Bluetooth MAC address infor to nvs flash */
    if (memcmp(mPartitionTable.BasicInfor.ProductDescription + 6, re_derived_mac_addr, 6) != 0) {
        for (int i = 0; i < 3; i++) {
            mPartitionTable.BasicInfor.ProductDescription[6 + i] = (derived_mac_addr[2 * i] << 8) + derived_mac_addr[2 * i + 1];
        }
        uiIndex = 0x0221 - 1; // Bluetooth MAC start address: 0x0221 - 1, temporary storage Product Description
        uiSize = 3;
        while (uiSize) {
            CFG_vSaveConfig(uiIndex++);
            uiSize--;
        }
    } else {
        ESP_LOGI(TAG, "Bluetooth MAC already storaged in ProductDescription area.");
    }

    /* write Bluetooth MAC address infor to nvs flash IoT area */
    // esp_log_buffer_hex(TAG,mPartitionTable.tIotConfig.usBT_MAC,6);
    if (memcmp(mPartitionTable.tIotConfig.usBT_MAC, re_derived_mac_addr, 6) != 0) {
        for (int i = 0; i < 3; i++) {
            mPartitionTable.tIotConfig.usBT_MAC[i] = (derived_mac_addr[2 * i] << 8) + derived_mac_addr[2 * i + 1];
        }
        uiIndex = 0x0070 - 1; // Bluetooth MAC start address: 0x0070 - 1, storage IoT config area
        uiSize = 3;
        while (uiSize) {
            CFG_vSaveConfig(uiIndex++);
            uiSize--;
        }
    } else {
        ESP_LOGI(TAG, "Bluetooth MAC already storaged in IoT store area.");
    }

    // Get MAC address for Ethernet
    ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_ETH));
    ESP_LOGW("Ethernet MAC", "\t0x %02x %02x %02x %02x %02x %02x",
        derived_mac_addr[0], derived_mac_addr[1], derived_mac_addr[2],
        derived_mac_addr[3], derived_mac_addr[4], derived_mac_addr[5]);
    // store reverse MAC bytes with 2 bytes
    for (int i = 0; i < 3; i++) {
        tmp = derived_mac_addr[2 * i];
        re_derived_mac_addr[2 * i] = derived_mac_addr[2 * i + 1];
        re_derived_mac_addr[2 * i + 1] = tmp;
    }

    /* writeEthernet MAC address infor to nvs flash */
    if (memcmp(mPartitionTable.BasicInfor.ProductDescription + 9, re_derived_mac_addr, 6) != 0) {
        for (int i = 0; i < 3; i++) {
            mPartitionTable.BasicInfor.ProductDescription[9 + i] = (derived_mac_addr[2 * i] << 8) + derived_mac_addr[2 * i + 1];
        }
        uiIndex = 0x0224 - 1; // Ethernet MAC start address: 0x0224 - 1, temporary storage Product Description
        uiSize = 3;
        while (uiSize) {
            CFG_vSaveConfig(uiIndex++);
            uiSize--;
        }
    } else {
        ESP_LOGI(TAG, "Ethernet MAC already storaged in ProductDescription area.");
    }
}

/*the system restart wiht software*/
void vEsp32Restart()
{
    fflush(stdout);
    esp_restart();
}

extern uint8_t mEthConnected;
extern uint8_t start_myHTTP;

void app_main(void)
{
    printf("app_main start Free memory: on chip = %.2f Kbytes,total = %.2f Kbytes %s\n", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_DMA) / 1024.0, esp_get_free_heap_size() / 1024.0, __FILE__);
    http_sem = xSemaphoreCreateBinary();
    xSemaphoreGive(http_sem);
    ESP_LOGI(TAG, "System start!");
    CFG_vInit();
    Main_Create_Task_Queue();
    Main_Get_ESP32_MAC_Addr();
    DEV_vInit();
    Main_Write_Vesion_Number_To_NVS();
    Main_Hardware_Config();
    ModbusTCP_handle_sem = xSemaphoreCreateBinary();
    xSemaphoreGive(ModbusTCP_handle_sem);
    printf("app_main End Free memory: on chip = %.2f Kbytes,total = %.2f Kbytes %s\n", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_DMA) / 1024.0, esp_get_free_heap_size() / 1024.0, __FILE__);
    // while (1) {
    //     vTaskDelay(pdMS_TO_TICKS(10000));
    // }
}
